﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda INodeList_ZIP</summary>
    public class INodeList_ZIP : INodeList
    {

        /// <summary>Trieda INodeComparer</summary>
        protected class INodeComparer : System.Collections.Generic.IComparer<INode>
        {
            protected delegate int OnCompare(INode N1, INode N2);
            protected OnCompare FCompareMethod; // Metoda porovnania

            /// <summary>Porovnanie podla nazvu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Asc(INode N1, INode N2)
            {
                return string.Compare(((INodeData_ZIP)N1.NodeData).ZIP_ItemName, ((INodeData_ZIP)N2.NodeData).ZIP_ItemName);
            }
            /// <summary>Porovnanie podla nazvu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Desc(INode N1, INode N2)
            {
                return -string.Compare(((INodeData_ZIP)N1.NodeData).ZIP_ItemName, ((INodeData_ZIP)N2.NodeData).ZIP_ItemName);
            }
            /// <summary>Porovnanie podla pripony asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Asc(INode N1, INode N2)
            {
                int R = string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Asc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla pripony desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Desc(INode N1, INode N2)
            {
                int R = -string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Desc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla velkosti asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Asc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Asc(N1, N2);
                return N1.Size > N2.Size ? 1 : -1;
            }
            /// <summary>Porovnanie podla velkosti desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Desc(INode N1, INode N2)
            {
                if (((INodeData_ZIP)N1.NodeData).ZIP_OriginalSize == ((INodeData_ZIP)N2.NodeData).ZIP_OriginalSize) return Compare_0_Desc(N1, N2);
                return ((INodeData_ZIP)N1.NodeData).ZIP_OriginalSize > ((INodeData_ZIP)N2.NodeData).ZIP_OriginalSize ? -1 : 1;
            }
            /// <summary>Porovnanie podla komprimovanej velkosti</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_3_Asc(INode N1, INode N2)
            {
                if (((INodeData_ZIP)N1.NodeData).ZIP_CompressedSize == ((INodeData_ZIP)N2.NodeData).ZIP_CompressedSize) return Compare_0_Asc(N1, N2);
                return ((INodeData_ZIP)N1.NodeData).ZIP_CompressedSize > ((INodeData_ZIP)N2.NodeData).ZIP_CompressedSize ? 1 : -1;
            }
            /// <summary>Porovnanie podla komprimovanej velkosti</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_3_Desc(INode N1, INode N2)
            {
                if (((INodeData_ZIP)N1.NodeData).ZIP_CompressedSize == ((INodeData_ZIP)N2.NodeData).ZIP_CompressedSize) return Compare_0_Asc(N1, N2);
                return ((INodeData_ZIP)N1.NodeData).ZIP_CompressedSize > ((INodeData_ZIP)N2.NodeData).ZIP_CompressedSize ? -1 : 1;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Asc(INode N1, INode N2)
            {
                int R = N1.DLastModify.CompareTo(N2.DLastModify);
                if (R == 0) return Compare_0_Asc(N1, N2);
                return R;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Desc(INode N1, INode N2)
            {
                int R = -N1.DLastModify.CompareTo(N2.DLastModify); ;
                if (R == 0) return Compare_0_Desc(N1, N2);
                return R;
            }

            /// <summary>Konstruktor</summary>
            /// <param name="pCol">triediaci stlpec</param>
            /// <param name="pDirection">smer</param>
            public INodeComparer(int pCol, bool pDirection)
            {
                switch (pCol)
                {
                    case 5: if (pDirection) FCompareMethod = Compare_4_Asc; else FCompareMethod = Compare_4_Desc; break;
                    case 3: if (pDirection) FCompareMethod = Compare_3_Asc; else FCompareMethod = Compare_3_Desc; break;
                    case 2: if (pDirection) FCompareMethod = Compare_2_Asc; else FCompareMethod = Compare_2_Desc; break;
                    case 1: if (pDirection) FCompareMethod = Compare_1_Asc; else FCompareMethod = Compare_1_Desc; break;
                    default: if (pDirection) FCompareMethod = Compare_0_Asc; else FCompareMethod = Compare_0_Desc; break;
                }
            }

            /// <summary>Compare metoda</summary>
            /// <param name="x">objekt 1</param>
            /// <param name="y">objekt 2</param>
            /// <returns>vysledok porovnania</returns>
            int System.Collections.Generic.IComparer<INode>.Compare(INode x, INode y)
            {
                return FCompareMethod(x, y); // Volam porovnavaciu metodu
            }
        }
        
        protected string FBaseArchiveFileName; // Nazov archivu
        protected string FRelativePath; // Relativna cesta
        protected string FPassword; // Heslo pre spracovanie

        protected Ionic.Zip.ZipFile FExpand_Archive; // Premenne pre proces expandovania
        protected System.Collections.Generic.List<INode> FExpand_Dirs;
        protected System.Collections.Generic.List<INode> FExpand_Files;
        protected int FExpand_TotalCount; // Pocitadlo vsetkych poloziek pri expande
        protected int FExpand_CurrentItem; // Aktualny zaznam

        protected Ionic.Zip.ZipFile FExtract_Archive; // Premenne pre proces extrahovania
        protected INode FExtract_CurrentItem;
        protected System.Collections.Generic.List<string> FExtract_ListOfItems;
        protected string FExtract_ListOfItemsRoot; // Spolocny zaciatok vsetkych poloziek
        protected int FExtract_CurrentItemIndex; // Aktualny zaznam
        protected Ionic.Crc.CrcCalculatorStream FExtract_CurrentItemReadStream;
        protected Ionic.Zip.ZipEntry FExtract_CurrentZipEntry;
        protected string FExtract_Password;
        protected IFileExplorer_ProgressForm_ExtractArchive FExtract_ProgressForm; // Progress formular pri procese testovania

        /// <summary>Property: CacheID</summary>
        public override string CacheID
        {
            get
            {
                return FBaseArchiveFileName.ToLower();
            }
        }
        /// <summary>Otvorenie cache pre citanie</summary>
        /// <returns>true / false</returns>
        public override bool BeginReadCache()
        {
            return false;
        }
        /// <summary>Zapis node do cache</summary>
        /// <param name="pNode">objekt</param>
        protected override void WriteNodeToCache(INode pNode)
        {
            if (!IsWriteCacheReady) return; // Ziadna cache?

            FCacheWriter.Write(pNode.ID);
            FCacheWriter.Write(((INodeData_ZIP)pNode.NodeData).ZIP_Attributes);
            FCacheWriter.Write(((INodeData_ZIP)pNode.NodeData).ZIP_CompressedSize);
            FCacheWriter.Write(((INodeData_ZIP)pNode.NodeData).ZIP_CRC);
            FCacheWriter.Write(((INodeData_ZIP)pNode.NodeData).ZIP_DModify.Ticks);
            FCacheWriter.Write(((INodeData_ZIP)pNode.NodeData).ZIP_ItemName);
            FCacheWriter.Write(((INodeData_ZIP)pNode.NodeData).ZIP_OriginalSize);
        }
        /// <summary>Nacitanie node z cache</summary>
        /// <returns>objekt alebo null pre koniec</returns>
        protected override bool ReadNodeFromCache(INode Result)
        {
            if (!IsReadCacheReady) return false;
            try
            {
                Result.ID = FCacheReader.ReadInt32(); // Nacitam
                Result.NodeData = new INodeData_ZIP();
                ((INodeData_ZIP)Result.NodeData).ZIP_Attributes = FCacheReader.ReadUInt32();
                ((INodeData_ZIP)Result.NodeData).ZIP_CompressedSize = FCacheReader.ReadInt64();
                ((INodeData_ZIP)Result.NodeData).ZIP_CRC = FCacheReader.ReadUInt32();
                ((INodeData_ZIP)Result.NodeData).ZIP_DModify = new DateTime(FCacheReader.ReadInt64());
                ((INodeData_ZIP)Result.NodeData).ZIP_ItemName = FCacheReader.ReadString();
                ((INodeData_ZIP)Result.NodeData).ZIP_OriginalSize = FCacheReader.ReadInt64();
                return true; // Vsetko OK
            }
            catch
            {
                return false;
            }
        }

        /// <summary>Konstruktor</summary>
        public INodeList_ZIP(string pArchiveFileName = "", string pRelativePath = "")
        {
            ID = INodeList.NODE_LIST_ID_ZIP_ARCHIVE;
            FColsCount = 8;
            FEnableVisibilityMask = 0xfe; FDefVisibilityMask = 0xff;
            FThreadExpandAvailable = true;
            FBaseArchiveFileName = pArchiveFileName; FRelativePath = pRelativePath;
            FPassword = null;
        }

        /// <summary>Ziskanie nazvu stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov alebo prazdny retazec</returns>
        public override string GetColumnName(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_1;
                case 1: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_2;
                case 2: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_3;
                case 3: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_4;
                case 4: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_5;
                case 5: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_6;
                case 6: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_7;
                case 7: return lang.NODE_LIST_ZIP_ARCHIVE_TEXT_8;
                default: return "";
            }
        }
        /// <summary>Ziskanie zarovnania stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>zarovnanie</returns>
        public override System.Windows.Forms.HorizontalAlignment GetColumnAlignment(int pIndex)
        {
            switch (pIndex)
            {
                case 2:
                case 3:
                    return System.Windows.Forms.HorizontalAlignment.Right;
                case 4:
                case 5:
                case 6:
                    return System.Windows.Forms.HorizontalAlignment.Center;
                default: return System.Windows.Forms.HorizontalAlignment.Left;
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string CurrentPath
        {
            get
            {
                return IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath);
            }
        }
        /// <summary>Property: KeyValue</summary>
        public override string KeyValue
        {
            get
            {
                if (FRelativePath == "") return IFileSystem.ExtractName(FBaseArchiveFileName).ToLower();
                return IFileSystem.ExtractName(IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath)).ToLower();
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string ParentPath
        {
            get
            {
                if (FRelativePath == "") return IFileSystem.ExtractPath(FBaseArchiveFileName);
                int I = FRelativePath.LastIndexOf('\\');
                if (I == -1) return FBaseArchiveFileName;
                return IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath.Substring(0, I));
            }
        }
        /// <summary>Test ci sa node moze expandovat</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeExpand(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_ZIP_ITEM:
                    {
                        return N.IsDirectory;
                    }
                default: return false;
            }
        }
        /// <summary>Ziskanie expandovacej cesty node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>cesta</returns>
        public override string GetNodeExpandPath(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return ""; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_ZIP_ITEM: return IFileSystem.AppendToPath(IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath), ((INodeData_ZIP)N.NodeData).ZIP_ItemName);
                default: return "";
            }
        }
        /// <summary>Property: DeviceRootPath</summary>
        public override string DeviceRootPath
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }
        /// <summary>Property: CanSelect</summary>
        public override bool CanSelect
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanSelectNode(INode pNode)
        {
            if (pNode == null) return false; // Ziskam platny node

            switch (pNode.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: CanSort</summary>
        public override bool CanSort
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test ci je mozne podla zadaneho stlpca triedit</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool IsSortColumn(int pIndex)
        {
            switch (pIndex)
            {
                case 4:
                case 6:
                case 7:
                    return false;
                default: return true;
            }
        }
        /// <summary>Property: Test ci je list archivom</summary>
        public override bool IsArchive
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: ArchiveName</summary>
        public override string ArchiveName
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }
        /// <summary>Property: IsCopySource</summary>
        public override bool IsCopySource
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: IsCopySourceItem</summary>
        public override bool IsCopySourceItem(int pIndex)
        {
            if (!IsCopySource) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }

        /// <summary>Zaciatok expandovania obsahu</summary>
        /// <param name="pFilter">objekt filtra</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int BeginExpand(INodeFilters pFilter = null)
        {
            FState = 1; // Nastavim stav expandovania
            FExpand_Archive = null;
            FExpand_Dirs = new System.Collections.Generic.List<INode>(); FExpand_Files = new System.Collections.Generic.List<INode>(); // Polia pre subory a priecinky
            FExpand_TotalCount = 0;
            FExpand_CurrentItem = 0;

            return 0; // Vsetko OK
        }
        /// <summary>Uzatvorenie aktualneho expandu</summary>
        public override void CloseExpand()
        {
            if (FExpand_Archive != null)
            {
                // Zaradim do zoznamu
                for (int i = 0; i < FExpand_Dirs.Count; i++) AddNode(FExpand_Dirs[i]);
                for (int i = 0; i < FExpand_Files.Count; i++) AddNode(FExpand_Files[i]);

                FExpand_Dirs.Clear(); FExpand_Dirs = null;
                FExpand_Files.Clear(); FExpand_Files = null;

                FExpand_Archive = (Ionic.Zip.ZipFile)ICore.DisposeObject(FExpand_Archive);
            }
            FState = 0; // Nastavim normalny stav
        }
        /// <summary>Expandovanie dalsieho zaznamu</summary>
        /// <param name="Result">ulozeny obsah najdeneho zaznamu alebo null ak sa ma zaznam pripojit do zoznamu</param>
        /// <returns>0 - ziaden dalsi zaznam, 1 - najdeny zaznam alebo kod chyby</returns>
        public override int ExpandNext(INodeFilters pFilter = null, INode Result = null)
        {
            try
            {
                if (FExpand_Archive == null) // Nepridany back node?
                {
                    if (Result == null)
                    {
                        INode N2 = new INode(); N2.ID = INode.NODE_ID_BACK_ITEM; AddNode(N2); // Vytvorim prvy back item node
                    }

                    FExpand_Archive = new Ionic.Zip.ZipFile(FBaseArchiveFileName, System.Text.Encoding.GetEncoding(852));
                }

                while (true)
                {
                    string RelP = FRelativePath == "" ? "" : FRelativePath.Replace('\\', '/') + "/"; // Testujem ci to patri do aktualnej urovne...
                    INode N = Result == null ? new INode() : Result; // Vyplnim
                    string RelName = "";

                    if (IsReadCacheReady) // Citanie z cache?
                    {
                        while (true)
                        {
                            if (!ReadNodeFromCache(N))
                            {
                                if (Result == null) N.Dispose();
                                return 0;
                            }
                            WriteNodeToCache(N);

                            RelName = ICore.DeleteLastExistingChar(((INodeData_ZIP)N.NodeData).ZIP_ItemName, '/');
                            FExpand_TotalCount++;

                            if (FRelativePath != "")
                            {
                                if (string.Compare(RelP, 0, RelName, 0, RelP.Length, false) != 0)
                                {
                                    if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_13, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                                    continue;
                                }
                                RelName = RelName.Substring(RelP.Length);
                            }
                            if (RelName.IndexOf('/') != -1)
                            {
                                if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_13, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                                continue;
                            }
                            ((INodeData_ZIP)N.NodeData).ZIP_ItemName = RelName;
                            if (Result == null)
                            {
                                if (N.IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                                if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_13, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                            }
                            FCachedContent = true;
                            return 1;
                        }
                    }


                    if (FExpand_CurrentItem >= FExpand_Archive.Count) return 0;

                    Ionic.Zip.ZipEntry E = FExpand_Archive[FExpand_CurrentItem++]; // Ziskam zaznam
                    N.ID = INode.NODE_ID_ZIP_ITEM;
                    N.NodeData = new INodeData_ZIP();
                    ((INodeData_ZIP)N.NodeData).ZIP_ItemName = E.FileName;
                    ((INodeData_ZIP)N.NodeData).ZIP_Attributes = (uint)E.Attributes;
                    ((INodeData_ZIP)N.NodeData).ZIP_OriginalSize = E.UncompressedSize;
                    ((INodeData_ZIP)N.NodeData).ZIP_CompressedSize = E.CompressedSize;
                    ((INodeData_ZIP)N.NodeData).ZIP_DModify = E.LastModified;
                    ((INodeData_ZIP)N.NodeData).ZIP_CRC = (uint)E.Crc;
                    ((INodeData_ZIP)N.NodeData).ZIP_Comment = E.Comment;
                    WriteNodeToCache(N); // Zapisem do cache

                    RelName = ICore.DeleteLastExistingChar(((INodeData_ZIP)N.NodeData).ZIP_ItemName, '/');
                    FExpand_TotalCount++;

                    if (FRelativePath != "")
                    {
                        if (string.Compare(RelP, 0, RelName, 0, RelP.Length, false) != 0)
                        {
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_13, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                            continue;
                        }
                        RelName = RelName.Substring(RelP.Length);
                    }
                    if (RelName.IndexOf('/') != -1)
                    {
                        if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_13, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                        continue;
                    }
                    ((INodeData_ZIP)N.NodeData).ZIP_ItemName = RelName; // Patri, ulozim relativne meno

                    if (Result == null)
                    {
                        if (N.IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                    }

                    return 1;
                }
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>Vytvorenie textov pre zobrazenie</summary>
        /// <param name="pNode">objekt node</param>
        public override void CreateDisplayStrings(INode pNode)
        {
            if (pNode.DisplayStrings != null) return; // Uz su vytvorenie?

            pNode.DisplayStrings = new string[ColsCount]; // Alokujem retazec
            switch (pNode.ID) // Podla typu node
            {
                case INode.NODE_ID_BACK_ITEM:
                    {
                        pNode.DisplayStrings[0] = ICore.BoundString("[", "..", "]", IApp.Settings.FileExplorer_DirsInBraces);
                        pNode.DisplayStrings[2] = FRelativePath == "" ? lang.NODE_LIST_ZIP_ARCHIVE_TEXT_9 : lang.NODE_LIST_ZIP_ARCHIVE_TEXT_10;
                        pNode.DefaultImageIndex = -1;
                    } break;
                case INode.NODE_ID_ZIP_ITEM:
                    {
                        if (pNode.IsDirectory)
                        {
                            pNode.DisplayStrings[0] = pNode.Name; // Len nazov
                            if (pNode.ValidSize) pNode.DisplayStrings[2] = ICore.Size2String((ulong)pNode.Size, IApp.Settings.FileExplorer_DisplaySizeMode);
                            else pNode.DisplayStrings[2] = lang.NODE_LIST_ZIP_ARCHIVE_TEXT_11;
                            pNode.DefaultImageIndex = 0;
                        }
                        else
                        {
                            pNode.DisplayStrings[0] = pNode.NameOnly; // Len nazov
                            if (pNode.DisplayStrings[0] == "") pNode.DisplayStrings[0] = pNode.Name; else pNode.DisplayStrings[1] = pNode.Ext; // Pripona
                            pNode.DisplayStrings[2] = ICore.Size2String((ulong)((INodeData_ZIP)pNode.NodeData).ZIP_OriginalSize, IApp.Settings.FileExplorer_DisplaySizeMode); // Velkost
                            pNode.DisplayStrings[3] = ICore.Size2String((ulong)((INodeData_ZIP)pNode.NodeData).ZIP_CompressedSize, IApp.Settings.FileExplorer_DisplaySizeMode); // Komprimovana velkost
                            pNode.DisplayStrings[4] = pNode.AttributesAsString;
                            pNode.DisplayStrings[5] = ICore.DateTime2Str(pNode.DLastModify);
                            pNode.DisplayStrings[6] = ((INodeData_ZIP)pNode.NodeData).ZIP_CRC.ToString("X8");
                            pNode.DisplayStrings[7] = ((INodeData_ZIP)pNode.NodeData).ZIP_Comment;
                            pNode.DefaultImageIndex = 1;
                        }
                    } break;
            }
        }
        /// <summary>Triedenie obsahu zoznamu</summary>
        /// <param name="pColumn">stlpec</param>
        /// <param name="pAsc">smer</param>
        public override void Sort(int pColumn, bool pAsc)
        {
            int S = IsBackNode(0) ? 1 : 0; // Urcim zaciatok
            if (DirsCount > 1)
            {
                FItems.Sort(S, DirsCount, new INodeComparer(0, pAsc));
            }
            if (FilesCount > 1)
            {
                FItems.Sort(S + DirsCount, FilesCount, new INodeComparer(pColumn, pAsc));
            }
        }
        /// <summary>Vytvorenie klonu zoznamu</summary>
        /// <returns>objekt zoznamu</returns>
        public override INodeList CloneList()
        {
            return new INodeList_ZIP(FBaseArchiveFileName, FRelativePath);
        }

        /// <summary>Ziskanie statistickych informacii pre proces extrahovania</summary>
        /// <param name="ResultStatData">vysledna stat. data</param>
        /// <param name="pItems">zoznam poloziek pre spocitanie</param>
        /// <param name="pBreakState">premenna pre oznamenie o preruseni spracovania</param>
        /// <returns>true / false</returns>
        public override bool Run_GetExtractStatsInfo(IComputeOccupiedSpaceData ResultStatData, System.Collections.Generic.List<string> pItems = null, IThrSafeVariable pBreakState = null)
        {
            string FN = "";

            try // Test hlavicky a nacitanie dat
            {
                BeginSourceExtractMode(pItems, null);
                using (INode N = new INode())
                {
                    while (true)
                    {
                        N.Clear();
                        if (ExtractMode_GetNextSourceItem(N) != 1) break;
                        if (ExtractMode_CurrentNeedExpand(ref FN))
                        {
                            if (N.IsDirectory)
                            {
                                ResultStatData.AddDir();
                            }
                            else
                            {
                                ResultStatData.AddFile(((INodeData_ZIP)N.NodeData).ZIP_OriginalSize);
                            }
                        }
                    }
                }
                CloseExtractMode();
                return true;
            }
            catch
            {
                return false; // Chyba
            }
        }
        /// <summary>Spustenie procesu kontroly archivu RAR</summary>
        /// <param name="pErrorMsg">chybova sprava</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public override bool TestArchive(out string pErrorMsg, IFileExplorer_ProgressForm_TestArchive pProgressForm = null)
        {
            pErrorMsg = ""; // Inicializacia
            if (pProgressForm != null) pProgressForm.StartArchive(FBaseArchiveFileName, "ZIP");

            byte[] Buffer = new byte[65536];

            try
            {
                string Passwd = null;
                using (Ionic.Zip.ZipFile Archive = new Ionic.Zip.ZipFile(FBaseArchiveFileName))
                {
                    foreach (Ionic.Zip.ZipEntry E in Archive)
                    {
                        if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return false;
                        if (E.Encryption != Ionic.Zip.EncryptionAlgorithm.None)
                        {
                            if (Passwd == null) 
                            {
                                Passwd = IApp.GlobalData.GetPassword(PasswordCacheID); // Poziadam o heslo
                                if (Passwd == null)
                                {
                                    if (pProgressForm == null) Passwd = "";
                                    else
                                    {
                                        Passwd = "";
                                        if (!pProgressForm.ShowEditor_EditString(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_14, ref Passwd, false, -1, null, null, true)) return false;
                                    }
                                    IApp.GlobalData.SavePassword(PasswordCacheID, Passwd); // Ulozim do cache
                                }
                            }
                            E.Password = Passwd;
                        }

                        string FN = ICore.DeleteLastExistingChar(E.FileName, '/');
                        int I = FN.LastIndexOf('/');
                        if (I != -1) FN = FN.Substring(I + 1); // Mam relativne meno

                        if (pProgressForm != null) // Zobrazuje sa progress?
                        {
                            if (E.IsDirectory) pProgressForm.AddDir();
                            else pProgressForm.StartFile(FN);
                        }

                        if (E.IsDirectory) continue; // Pri priecinku pokracujem

                        long TotalReaded = 0;
                        using (Ionic.Crc.CrcCalculatorStream Str = E.OpenReader())
                        {
                            while(true) {
                                int C = Str.Read(Buffer, 0, 65536);
                                if (C <= 0) break;
                                TotalReaded += C;
                                if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return false;
                            }
                            if (TotalReaded != E.UncompressedSize)
                            {
                                pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, "ZIP");
                                return false;
                            }
                            if ((Passwd == null) && (E.Crc != Str.Crc))
                            {
                                pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, "ZIP");
                                return false;
                            }
                        }
                        if (pProgressForm != null) pProgressForm.FinishFile();
                    }
                }
                return true; // Test prebehol OK
            }
            catch(Ionic.Zip.ZipException E)
            {
                if (E.Message.ToLower().Contains("unsupported compression method")) pErrorMsg = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_16, "ZIP");
                else
                {
                    if (E.Message.ToLower().Contains("bad password"))
                    {
                        IApp.GlobalData.SavePassword(PasswordCacheID, null); // Zrusim heslo z cache
                        pErrorMsg = string.Format(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_17, "ZIP");
                    }
                    else pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, "ZIP");
                }
                return false; // Chyba
            }
        }

        /// <summary>Nastavenie zoznamu do modu zdroja extrahovania</summary>
        /// <param name="pItemsToExtract">polozky na extrahovanie</param>
        /// <param name="pProgressForm">progress formular</param>
        public override void BeginSourceExtractMode(System.Collections.Generic.List<string> pItemsToExtract = null, IFileExplorer_ProgressForm_ExtractArchive pProgressForm = null)
        {
            FExtract_Archive = null;
            FExtract_CurrentItem = new INode(); FExtract_CurrentItem.NodeData = new INodeData_ZIP();
            FExtract_CurrentItemReadStream = null;
            FExtract_CurrentZipEntry = null;
            FExtract_ProgressForm = pProgressForm;
            CopyMode_NativeDataBuffer = new byte[MAX_COPY_BUFFER_SIZE];

            if (pItemsToExtract == null) FExtract_ListOfItems = null;
            else
            {
                FExtract_ListOfItemsRoot = null;
                FExtract_ListOfItems = new System.Collections.Generic.List<string>();
                foreach (string S in pItemsToExtract) // Vytvorim relativne cesty
                {
                    int I = S.LastIndexOf(":\\");
                    if (I != -1)
                    {
                        string S1 = S.Substring(I + 2);
                        FExtract_ListOfItems.Add(S1);
                        if (FExtract_ListOfItemsRoot == null) FExtract_ListOfItemsRoot = S1;
                        else
                        {
                            if (FExtract_ListOfItemsRoot.Length > 0)
                            {
                                int i;
                                for (i = 0; i < FExtract_ListOfItemsRoot.Length; i++)
                                {
                                    if (i >= S1.Length) break;
                                    if (char.ToLower(FExtract_ListOfItemsRoot[i]) != char.ToLower(S1[i])) break;
                                }
                                if (i != FExtract_ListOfItemsRoot.Length) FExtract_ListOfItemsRoot = i == 0 ? "" : FExtract_ListOfItemsRoot.Substring(0, i);
                            }
                        }
                    }
                }
                if (string.IsNullOrEmpty(FExtract_ListOfItemsRoot)) FExtract_ListOfItemsRoot = "";
                else
                {
                    int I = FExtract_ListOfItemsRoot.LastIndexOf('\\');
                    FExtract_ListOfItemsRoot = I == -1 ? "" : FExtract_ListOfItemsRoot.Substring(0, I + 1);
                }
                FExtractMode_ItemsToExpandList = new System.Collections.Generic.Dictionary<string, int>(); // Vytvorim cache poloziek
                foreach (string FN in pItemsToExtract) FExtractMode_ItemsToExpandList.Add(FN.Substring(FBaseArchiveFileName.Length + 2).ToLower(), 0);
            }
        }
        /// <summary>Uzatvorenie modu extrahovania</summary>
        public override void CloseExtractMode()
        {
            FExtract_Archive = (Ionic.Zip.ZipFile)ICore.DisposeObject(FExtract_Archive); // Uzatvorim
            FExtract_CurrentItem = (INode)ICore.DisposeObject(FExtract_CurrentItem);
            FExtract_CurrentItemReadStream = (Ionic.Crc.CrcCalculatorStream)ICore.DisposeObject(FExtract_CurrentItemReadStream);
            CopyMode_NativeDataBuffer = null;
        }
        /// <summary>Ziskanie nazvu aktualneho spracovavaneho zaznamu</summary>
        /// <returns>nazov</returns>
        public override string ExtractMode_CurrentName()
        {
            return FExtract_CurrentItem.Name;
        }
        /// <summary>Test potreby extrahovania aktualneho zaznamu</summary>
        /// <param name="DestRelativePath">vysledna relativna cesta</param>
        /// <returns>true / false</returns>
        public override bool ExtractMode_CurrentNeedExpand(ref string DestRelativePath)
        {
            return NeedToBeExtracted(FExtract_ListOfItemsRoot, FExtract_CurrentItem.RelativeName, FExtract_ListOfItems, ref DestRelativePath); // Ma sa extrahovat?
        }
        /// <summary>Test ci zadany objekt je potrebne extrahovat</summary>
        /// <param name="pSourceRoot">spolocny root zoznamu</param>
        /// <param name="pRelativeName">nazov objektu</param>
        /// <param name="pList">zoznam objektov pre extrahovanie</param>
        /// <param name="DestRelativePath">vysledna relativna cesta</param>
        /// <returns>true / false</returns>
        public static bool NeedToBeExtracted(string pSourceRoot, string pRelativeName, System.Collections.Generic.List<string> pList, ref string DestRelativePath)
        {
            if (pList == null) return true; // Vsetky?

            foreach (string S in pList) // Prechadzam zoznam
            {
                if (pRelativeName.Length < S.Length) continue; // Test dlzky
                if (string.Compare(pRelativeName, S, false) == 0)
                {
                    if (DestRelativePath == "") return true;
                    DestRelativePath = DestRelativePath.Substring(pSourceRoot.Length);
                    return true;
                }
                string S1 = S + "\\";
                if (string.Compare(pRelativeName, 0, S1, 0, S1.Length, false) == 0)
                {
                    if (DestRelativePath == "") return true;
                    DestRelativePath = DestRelativePath.Substring(pSourceRoot.Length);
                    return true;
                }
            }
            return false;
        }
        /// <summary>Ziskanie dalsieho zaznamu na extrahovanie</summary>
        /// <param name="Result">vysledne data</param>
        /// <returns>0 - koniec, 1 - platny zaznam, alebo kod chyby</returns>
        public override int ExtractMode_GetNextSourceItem(INode Result)
        {
            try
            {
                if (FExtract_Archive == null)
                {
                    FExtract_Archive = new Ionic.Zip.ZipFile(FBaseArchiveFileName, System.Text.Encoding.GetEncoding(852));
                    FExtract_CurrentItemIndex = 0;
                }

                if (FExtract_CurrentItemIndex >= FExtract_Archive.Count) return 0;
                FExtract_CurrentZipEntry = FExtract_Archive[FExtract_CurrentItemIndex++];

                FExtract_CurrentItem.ID = INode.NODE_ID_ZIP_ITEM;
                FExtract_CurrentItem.NodeData = new INodeData_ZIP();
                ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_ItemName = FExtract_CurrentZipEntry.FileName;
                ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_Attributes = (uint)FExtract_CurrentZipEntry.Attributes;
                ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_OriginalSize = FExtract_CurrentZipEntry.UncompressedSize;
                ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_CompressedSize = FExtract_CurrentZipEntry.CompressedSize;
                ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_DModify = FExtract_CurrentZipEntry.LastModified;
                ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_CRC = (uint)FExtract_CurrentZipEntry.Crc;
                FExtract_CurrentItem.RelativeName = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_ItemName.Replace('/', '\\');

                Result.ID = FExtract_CurrentItem.ID;
                Result.NodeData = new INodeData_ZIP();
                ((INodeData_ZIP)Result.NodeData).ZIP_ItemName = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_ItemName;
                ((INodeData_ZIP)Result.NodeData).ZIP_Attributes = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_Attributes;
                ((INodeData_ZIP)Result.NodeData).ZIP_OriginalSize = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_OriginalSize;
                ((INodeData_ZIP)Result.NodeData).ZIP_CompressedSize = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_CompressedSize;
                ((INodeData_ZIP)Result.NodeData).ZIP_DModify = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_DModify;
                ((INodeData_ZIP)Result.NodeData).ZIP_CRC = ((INodeData_ZIP)FExtract_CurrentItem.NodeData).ZIP_CRC;
                Result.RelativeName = FExtract_CurrentItem.RelativeName;

                return 1;
            }
            catch
            {
                return -1;
            }
        }
        /// <summary>Otvorenie aktualneho suboru na citanie</summary>
        /// <returns>0 alebo kod chyby</returns>
        public override int ExtractMode_OpenCurrentFileForRead()
        {
            while (true)
            {
                try
                {
                    if (FExtract_CurrentZipEntry.Encryption != Ionic.Zip.EncryptionAlgorithm.None)
                    {
                        if (FExtract_Password == null)
                        {
                            FExtract_Password = IApp.GlobalData.GetPassword(PasswordCacheID); // Poziadam o heslo
                            if (FExtract_Password == null)
                            {
                                if (FExtract_ProgressForm == null) FExtract_Password = "";
                                else
                                {
                                    FExtract_Password = "";
                                    if (!FExtract_ProgressForm.ShowEditor_EditString(lang.NODE_LIST_ZIP_ARCHIVE_TEXT_14, ref FExtract_Password, false, -1, null, null, true)) return IFileSystem.FS_ERROR_USER_ABORTED;
                                }
                                IApp.GlobalData.SavePassword(PasswordCacheID, FExtract_Password); // Ulozim do cache
                            }
                        }
                        FExtract_CurrentZipEntry.Password = FExtract_Password;
                    }
                    FExtract_CurrentItemReadStream = FExtract_CurrentZipEntry.OpenReader();
                    return 0;
                }
                catch (Ionic.Zip.ZipException E)
                {
                    if (E.Message.ToLower().Contains("bad password"))
                    {
                        IApp.GlobalData.SavePassword(PasswordCacheID, null); // Vymazem heslo z cache
                        FExtract_Password = null;
                    }
                    else
                    {
                        return IFileSystem.FS_ERROR_UNKNOWN;
                    }
                }
            }
        }
        /// <summary>Uzatvorenie aktualneho suboru otvoreneho na citanie</summary>
        public override void ExtractMode_CloseReadFile()
        {
            FExtract_CurrentItemReadStream = (Ionic.Crc.CrcCalculatorStream)ICore.DisposeObject(FExtract_CurrentItemReadStream);
        }
        /// <summary>Nacitanie obsahu</summary>
        /// <param name="pMaxLength">max. dlzka</param>
        /// <param name="pResultBuffer">vysledny buffer alebo null pre interny</param>
        /// <returns>pocet nacitanych bajtov alebo kod chyby</returns>
        public override int ExtractMode_ReadFile(int pMaxLength, byte[] pResultBuffer)
        {
            try
            {
                return FExtract_CurrentItemReadStream.Read(pResultBuffer, 0, pMaxLength);
            }
            catch
            {
                return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }

        /// <summary>Spustenie procesu vytvorenia archivu</summary>
        /// <param name="pData">data</param>
        /// <param name="pItems">zoznam poloziek na archivaciu</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public static bool Run_CreateArchive_ZIP(ICompressionDataStr pData, System.Collections.Generic.List<string> pItems, IFileExplorer_ProgressForm_CompressItems pProgressForm = null)
        {
            IConfirmationFlags Flags = new IConfirmationFlags();
            int R;

            INodeList SourceList = INodeList.CreateNodeList(IFileSystem.ExtractPath(pItems[0]));
            if (SourceList == null) return false; // Chybna zdrojova cesta?
            using (SourceList)
            {
                INodeList DestList = INodeList.CreateNodeList(IFileSystem.ExtractPath(pData.DestinationArchiveName));
                if (DestList == null) return false; // Chybna cielova cesta?
                using (DestList)
                {
                    SourceList.BeginSourceCopyMode();
                    DestList.BeginDestinationCopyMode();

                    System.IO.Stream DestStream_File = null;
                    Ionic.Zip.ZipOutputStream DestStream = null;

                    while (true)
                    {
                        DestStream_File = DestList.CopyMode_CreateStreamForWrite(IFileSystem.ExtractName(pData.DestinationArchiveName), out R, Flags.ForceOverwriteDestinationFile, Flags.ForceOverwriteReadOnlyDestinationFile, Flags.ForceOverwriteSystemDestinationFile, Flags.ForceOverwriteSystemDestinationFile); // Vytvorim cielovy subor

                        if (R == 0) break; // OK..

                        switch (R)
                        {
                            case IFileSystem.FS_ERROR_FILE_EXISTS:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_8_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_8_2, lang.FILE_EXPLORER_TEXT_39_8_3, ref Flags.OverwriteDestinationFile)) return false;
                                } break;
                            case IFileSystem.FS_ERROR_READ_ONLY_ATTRIBUTE:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_9_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_9_2, lang.FILE_EXPLORER_TEXT_39_9_3, ref Flags.OverwriteReadOnlyDestinationFile)) return false;
                                } break;
                            case IFileSystem.FS_ERROR_SYSTEM_ATTRIBUTE:
                            case IFileSystem.FS_ERROR_HIDDEN_ATTRIBUTE:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_10_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_10_2, lang.FILE_EXPLORER_TEXT_39_10_3, ref Flags.OverwriteSystemDestinationFile)) return false;
                                } break;
                            default:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_11_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_11_2, lang.FILE_EXPLORER_TEXT_39_11_3, ref Flags.CreateDestinationFileError)) return false;
                                } break;
                        }
                    }

                    DestStream = new Ionic.Zip.ZipOutputStream(DestStream_File); // Vytvorim ZIP stream
                    DestStream.EnableZip64 = Ionic.Zip.Zip64Option.AsNecessary;

                    bool IsFolder;
                    foreach (string FN in pItems)
                    {
                        if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return false;

                        string RelFN = SourceList.CopyMode_MakeRelative(FN, out IsFolder);
                        if (RelFN == "") continue;

                        if (IsFolder)
                        {
                            if (Run_CreateArchive_ZIP_AddDir(Flags, pData, DestStream, RelFN, SourceList, null, pProgressForm) == -1)
                            {
                                DestStream.Close(); DestStream.Dispose();
                                DestList.CopyMode_CloseStreamForWrite(DestStream_File, true);
                                return false;
                            }
                        }
                        else
                        {
                            if (Run_CreateArchive_ZIP_AddFile(Flags, pData, DestStream, RelFN, SourceList, null, pProgressForm) == -1)
                            {
                                DestStream.Close(); DestStream.Dispose();
                                DestList.CopyMode_CloseStreamForWrite(DestStream_File, true);
                                return false;
                            }
                        }
                    }

                    DestStream.Close(); DestStream.Dispose();
                    DestList.CopyMode_CloseStreamForWrite(DestStream_File, false);
                }
            }
            return true; // OK
        }
        /// <summary>Zaradenie priecinku do archivu</summary>
        /// <param name="pData">data</param>
        /// <param name="pArchive">objekt archivu</param>
        /// <param name="pName">nazov priecinku</param>
        /// <param name="pSource">zdrojovy zoznam</param>
        /// <param name="pNodeInfo">informacia o priecinku</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>0 - OK, 1 - preskocene, -1 prerusenie</returns>
        public static int Run_CreateArchive_ZIP_AddFile(IConfirmationFlags pFlags, ICompressionDataStr pData, Ionic.Zip.ZipOutputStream pArchive, string pName, INodeList pSource, INode pNodeInfo = null, IFileExplorer_ProgressForm_CompressItems pProgressForm = null)
        {
            byte[] Buffer = new byte[MAX_COPY_BUFFER_SIZE];

            DateTime DModify = pNodeInfo == null ? pSource.CopyMode_GetModifyDate(pName) : pNodeInfo.DLastModify; // Ziskam datum modifikacie
            long Size = pNodeInfo == null ? pSource.CopyMode_GetSize(pName) : pNodeInfo.Size; // Ziskam dlzku
            uint Attr = pNodeInfo == null ? pSource.CopyMode_GetAttributes(pName) : pNodeInfo.Attributes;

            if (Size > 0) // Subor ma nenulovu dlzku?
            {
                int R;
                while (true)
                {
                    R = pSource.CopyMode_OpenReadFile(pName, null); // Otvorim zdrojovy subor
                    if (R == 0) break;
                    switch (R)
                    {
                        default:
                            {
                                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_7_1, pSource.CopyMode_MakeSourceFullPath(pName)), lang.FILE_EXPLORER_TEXT_39_7_2, lang.FILE_EXPLORER_TEXT_39_7_3, ref pFlags.OpenSourceFileError)) return -1;
                            } break;
                    }
                }
            }

            if (pProgressForm != null) pProgressForm.SetCurrentFileSize(Size, pSource.CopyMode_MakeSourceFullPath(pName));

            while (true)
            {
                try
                {
                    Ionic.Zip.ZipEntry E = pArchive.PutNextEntry(pName);
                    E.AlternateEncoding = System.Text.Encoding.UTF8; E.AlternateEncodingUsage = Ionic.Zip.ZipOption.AsNecessary; // Nastavim alternativne kodovanie
                    E.ModifiedTime = DModify; E.Attributes = (System.IO.FileAttributes)Attr; // Nastavim datum modifikacie a atributy
                    E.CompressionLevel = (Ionic.Zlib.CompressionLevel)pData.ZIPCompression_Level;
                    E.Encryption = (Ionic.Zip.EncryptionAlgorithm)pData.ZIPEncryptionType;
                    if (pData.ZIPEncryptionType != 0) E.Password = pData.ZIPPassword;
                    break;
                }
                catch // Chyba
                {
                }
                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_13_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_13_2, lang.FILE_EXPLORER_TEXT_39_13_3, ref pFlags.CreateDestinationFileError)) return -1;
            }

            if (Size > 0)
            {
                int C;
                while (true)
                {
                    if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return -1;
                    while (true)
                    {
                        C = pSource.CopyMode_ReadFile(Buffer.Length, Buffer);
                        if (C >= 0) break; // OK?
                        if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_12_1, pSource.CopyMode_MakeSourceFullPath(pName)), lang.FILE_EXPLORER_TEXT_39_12_2, lang.FILE_EXPLORER_TEXT_39_12_3, ref pFlags.ReadSourceFileError)) return -1;
                    }

                    if (C == 0) break; // Koniec citania?
                    pArchive.Write(Buffer, 0, C);
                    if (pProgressForm != null) pProgressForm.AddTransferredDataSize(C);
                }
            }

            pSource.CopyMode_CloseReadFile();
            if (pProgressForm != null)
            {
                pProgressForm.AddTransferredDataSize(0);
                pProgressForm.AddFile(false);
            }


            return 0; // Vsetko OK
        }
        /// <summary>Zaradenie priecinku do archivu</summary>
        /// <param name="pData">data</param>
        /// <param name="pArchive">objekt archivu</param>
        /// <param name="pName">nazov priecinku</param>
        /// <param name="pSource">zdrojovy zoznam</param>
        /// <param name="pNodeInfo">informacia o priecinku</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>0 - OK, 1 - preskocene, -1 prerusenie</returns>
        public static int Run_CreateArchive_ZIP_AddDir(IConfirmationFlags pFlags, ICompressionDataStr pData, Ionic.Zip.ZipOutputStream pArchive, string pName, INodeList pSource, INode pNodeInfo = null, IFileExplorer_ProgressForm_CompressItems pProgressForm = null)
        {
            DateTime DModify = pNodeInfo == null ? pSource.CopyMode_GetModifyDate(pName) : pNodeInfo.DLastModify;
            uint Attr = pNodeInfo == null ? pSource.CopyMode_GetAttributes(pName) : pNodeInfo.Attributes;
            while (true)
            {
                try
                {
                    Ionic.Zip.ZipEntry E = pArchive.PutNextEntry(pName); // Vytvorim priecinok
                    E.AlternateEncoding = System.Text.Encoding.UTF8; E.AlternateEncodingUsage = Ionic.Zip.ZipOption.AsNecessary; // Nastavim alternativne kodovanie
                    E.ModifiedTime = DModify; E.Attributes = (System.IO.FileAttributes)Attr;
                    E.CompressionLevel = (Ionic.Zlib.CompressionLevel)pData.ZIPCompression_Level;
                    E.Encryption = (Ionic.Zip.EncryptionAlgorithm)pData.ZIPEncryptionType;
                    if (pData.ZIPEncryptionType != 0) E.Password = pData.ZIPPassword;
                    pProgressForm.AddDir();
                    break;
                }
                catch
                {
                }
                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_13_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_13_2, lang.FILE_EXPLORER_TEXT_39_13_3, ref pFlags.CreateDestinationFileError)) return -1;
            }

            INodeList L = pSource.CopyMode_CreateSourceList(pName);
            if (L == null) return 1;

            bool IsFolder;
            using (INode N = new INode())
            {
                using (L)
                {
                    if (L.BeginExpand() == 0)
                    {
                        while (true)
                        {
                            N.Clear();
                            if (L.ExpandNext(null, N) != 1) break;

                            if (pProgressForm != null)
                            {
                                if (pProgressForm.WaitForTerminate.BoolValue) return -1; // Test ukoncenia
                            }

                            if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return -1;

                            string RelFN = pSource.CopyMode_MakeRelative(IFileSystem.AppendToPath(L.CurrentPath, N.Name), out IsFolder, N.IsDirectory); // Ziskam relativnu cestu
                            if (RelFN != "") // Je platna?
                            {
                                if (IsFolder)
                                {
                                    if (Run_CreateArchive_ZIP_AddDir(pFlags, pData, pArchive, RelFN, pSource, N, pProgressForm) == -1) return -1;
                                }
                                else
                                {
                                    if (Run_CreateArchive_ZIP_AddFile(pFlags, pData, pArchive, RelFN, pSource, N, pProgressForm) == -1) return -1;
                                }
                            }
                        }
                        L.CloseExpand();
                    }
                }
            }
            return 0; // Vsetko OK
        }

    }
}
